/*
 * x86_64/regs.hh - Control and debug registers wrappers.
 * Copyright (C) 2007  Mikhail Vorozhtsov
 * See the LICENSE section of the README file for details.
 */

/* $Id$ */

#ifndef HEADER_X86_64_REGS_HH
#define HEADER_X86_64_REGS_HH

#include HEADER (utils,setters.hh)

START_NAMESPACE (x86_64)

union cr0_t
{
  struct
    {
      word_t PE : 1;
      word_t MP : 1;
      word_t EM : 1;
      word_t TS : 1;
      word_t ET : 1;
      word_t NE : 1;
      word_t : 10;
      word_t WP : 1;
      word_t : 1;
      word_t AM : 1;
      word_t : 10;
      word_t NW : 1;
      word_t CD : 1;
      word_t PG : 1;
#ifndef IN_32BIT_CODE
      u64_t : 32;
#endif
    };
  word_t raw;

  INLINE
  static cr0_t
  get ()
  {
    cr0_t result;
    asm volatile (
      "mov %%cr0, %0\n"
      : "=r"(result.raw)
    );
    return result;
  }

  INLINE
  void
  set ()
  {
    asm volatile ( 
      "mov %0, %%cr0\n"
      :
      : "r"(raw)
    );
  }

  UTILS_RAW_ZERO (cr0_t, word_t)

  UTILS_BOOL_SETTER (cr0_t, PE)
  UTILS_BOOL_SETTER (cr0_t, MP)
  UTILS_BOOL_SETTER (cr0_t, EM)
  UTILS_BOOL_SETTER (cr0_t, TS)
  UTILS_BOOL_SETTER (cr0_t, ET)
  UTILS_BOOL_SETTER (cr0_t, NE)
  UTILS_BOOL_SETTER (cr0_t, WP)
  UTILS_BOOL_SETTER (cr0_t, AM)
  UTILS_BOOL_SETTER (cr0_t, NW)
  UTILS_BOOL_SETTER (cr0_t, CD)
  UTILS_BOOL_SETTER (cr0_t, PG)
};

union cr3_t
{
  struct
    {
      word_t : 3;
      word_t PWT : 1;
      word_t PCD : 1;
      word_t : 7;
#ifdef IN_32BIT_CODE
      u32_t PD : 20;
#else
      u64_t PML4 : 40;
      u64_t : 12;
#endif
    };
  word_t raw;

  INLINE
  static cr3_t
  get ()
  {
    cr3_t result;
    asm volatile (
      "mov %%cr3, %0\n"
      : "=r"(result.raw)
    );
    return result;
  }

  INLINE
  void
  set ()
  {
    asm volatile ( 
      "mov %0, %%cr3\n"
      :
      : "r"(raw)
    );
  }

  UTILS_RAW_ZERO (cr3_t, word_t)

#ifdef IN_32BIT_CODE
  UTILS_SETTER (cr3_t, u32_t, PD)
#else
  UTILS_SETTER (cr3_t, u64_t, PML4)
#endif

  UTILS_BOOL_SETTER (cr3_t, PWT)
  UTILS_BOOL_SETTER (cr3_t, PCD)

  INLINE
  word_t
  get_ptr ()
  {
#ifdef IN_32BIT_CODE
    return (u32_t) PD << 12;
#else
    return (u64_t) PML4 << 12;
#endif
  }

  INLINE
  cr3_t &
  set_ptr (word_t ptr)
  {
#ifdef IN_32BIT_CODE
    PD = ptr >> 12;
#else
    PML4 = ptr >> 12;
#endif
    return *this;
  }
};

union cr4_t
{
  struct
    {
      word_t VME : 1;
      word_t PVI : 1;
      word_t TSD : 1;
      word_t DE : 1;
      word_t PSE : 1;
      word_t PAE : 1;
      word_t MCE : 1;
      word_t PGE : 1;
      word_t PCE : 1;
      word_t OSFXSR : 1;
      word_t OSX : 1;
#ifdef IN_32BIT_CODE
      u32_t : 21;
#else
      u64_t : 53;
#endif
    };
  word_t raw;

  INLINE
  static cr4_t
  get ()
  {
    cr4_t result;
    asm volatile (
      "mov %%cr4, %0\n"
      : "=r"(result.raw)
    );
    return result;
  }

  INLINE
  void
  set ()
  {
    asm volatile ( 
      "mov %0, %%cr4\n"
      :
      : "r"(raw)
    );
  }

  UTILS_RAW_ZERO (cr4_t, word_t)

  UTILS_BOOL_SETTER (cr4_t, VME)
  UTILS_BOOL_SETTER (cr4_t, PVI)
  UTILS_BOOL_SETTER (cr4_t, TSD)
  UTILS_BOOL_SETTER (cr4_t, DE)
  UTILS_BOOL_SETTER (cr4_t, PSE)
  UTILS_BOOL_SETTER (cr4_t, PAE)
  UTILS_BOOL_SETTER (cr4_t, MCE)
  UTILS_BOOL_SETTER (cr4_t, PGE)
  UTILS_BOOL_SETTER (cr4_t, PCE)
  UTILS_BOOL_SETTER (cr4_t, OSFXSR)
  UTILS_BOOL_SETTER (cr4_t, OSX)
};

union flags_t
{
  struct
    {
      word_t CF : 1;
      word_t : 1;
      word_t PF : 1;
      word_t : 1;
      word_t AF : 1;
      word_t : 1;
      word_t ZF : 1;
      word_t SF : 1;
      word_t TF : 1;
      word_t IF : 1;
      word_t DF : 1;
      word_t OF : 1;
      word_t IOPL : 2;
      word_t NT : 1;
      word_t : 1;
      word_t RF : 1;
      word_t VM : 1;
      word_t AC : 1;
      word_t VIF : 1;
      word_t VIP : 1;
      word_t ID : 1;
#ifdef IN_32BIT_CODE
      u32_t : 10;
#else
      u64_t : 42;
#endif
    };
  word_t raw;

  INLINE
  static flags_t
  get ()
  {
    flags_t result;
    asm volatile (
      "pushf\n"
      "pop %0\n"
      : "=r"(result.raw)
    );
    return result;
  }

  INLINE
  void
  set ()
  {
    asm volatile (
      "push %0\n"
      "popf\n"
      :
      : "r"(raw)
    );
  }

  UTILS_RAW_ZERO (flags_t, word_t)

  UTILS_BOOL_SETTER (flags_t, CF)
  UTILS_BOOL_SETTER (flags_t, PF)
  UTILS_BOOL_SETTER (flags_t, AF)
  UTILS_BOOL_SETTER (flags_t, ZF)
  UTILS_BOOL_SETTER (flags_t, SF)
  UTILS_BOOL_SETTER (flags_t, TF)
  UTILS_BOOL_SETTER (flags_t, IF)
  UTILS_BOOL_SETTER (flags_t, DF)
  UTILS_BOOL_SETTER (flags_t, OF)
  UTILS_SETTER (flags_t, u8_t, IOPL)
  UTILS_BOOL_SETTER (flags_t, NT)
  UTILS_BOOL_SETTER (flags_t, RF)
  UTILS_BOOL_SETTER (flags_t, VM)
  UTILS_BOOL_SETTER (flags_t, AC)
  UTILS_BOOL_SETTER (flags_t, VIF)
  UTILS_BOOL_SETTER (flags_t, VIP)
  UTILS_BOOL_SETTER (flags_t, ID)
};

union dr6_t
{
  struct
    {
      u64_t B0 : 1;
      u64_t B1 : 1;
      u64_t B2 : 1;
      u64_t B3 : 1;
      u64_t : 9;
      u64_t BD : 1;
      u64_t BS : 1;
      u64_t BT : 1;
      u64_t : 48;
    };
  u64_t raw;

  UTILS_RAW_ZERO (dr6_t, u64_t)
};

union dr7_t
{
  struct
    {
      u64_t L0 : 1;
      u64_t G0 : 1;
      u64_t L1 : 1;
      u64_t G1 : 1;
      u64_t L2 : 1;
      u64_t G2 : 1;
      u64_t L3 : 1;
      u64_t G3 : 1;
      u64_t LE : 1;
      u64_t GE : 1;
      u64_t : 3;
      u64_t GD: 1;
      u64_t : 2;
      u64_t RW0 : 2;
      u64_t LEN0 : 2;
      u64_t RW1 : 2;
      u64_t LEN1 : 2;
      u64_t RW2 : 2;
      u64_t LEN2 : 2;
      u64_t RW3 : 2;
      u64_t LEN3 : 2;
      u64_t : 32;
    };
  u64_t raw;

  UTILS_RAW_ZERO (dr7_t, u64_t)
};

END_NAMESPACE

#endif /* HEADER_X86_64_REGS_HH */

